home *** CD-ROM | disk | FTP | other *** search
/ Java Programmer's Toolkit / Java Programmer's Toolkit.iso / solaris2 / jdk / src / java / util / hashtabl.jav < prev    next >
Encoding:
Text File  |  1995-10-30  |  11.0 KB  |  411 lines

  1. /*
  2.  * @(#)Hashtable.java    1.29 95/09/28  
  3.  *
  4.  * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software
  7.  * and its documentation for NON-COMMERCIAL purposes and without
  8.  * fee is hereby granted provided that this copyright notice
  9.  * appears in all copies. Please refer to the file "copyright.html"
  10.  * for further important copyright and licensing information.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  13.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  14.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  15.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  16.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  17.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  18.  */
  19.  
  20. package java.util;
  21.  
  22. /**
  23.  * Hashtable collision list.
  24.  */
  25. class HashtableEntry {
  26.     int hash;
  27.     Object key;
  28.     Object value;
  29.     HashtableEntry next;
  30.  
  31.     protected Object clone() {
  32.     HashtableEntry entry = (HashtableEntry)super.clone();
  33.     entry.next = (next != null) ? (HashtableEntry)next.clone() : null;
  34.     return entry;
  35.     }
  36.  
  37.  
  38. }
  39.  
  40. /**
  41.  * Hashtable class. Maps keys to values. Any object can be used as
  42.  * a key and/or value.<p>
  43.  *
  44.  * To sucessfully store and retrieve objects from a hash table the
  45.  * object used as the key must implement the hashCode() and equals()
  46.  * methods.<p>
  47.  *
  48.  * This example creates a hashtable of numbers. It uses the names of
  49.  * the numbers as keys:
  50.  * <pre>
  51.  *    Hashtable numbers = new Hashtable();
  52.  *    numbers.put("one", new Integer(1));
  53.  *    numbers.put("two", new Integer(2));
  54.  *    numbers.put("three", new Integer(3));
  55.  * </pre>
  56.  * To retrieve a number use:
  57.  * <pre>
  58.  *    Integer n = (Integer)numbers.get("two");
  59.  *    if (n != null) {
  60.  *        System.out.println("two = " + n);
  61.  *    }
  62.  * </pre>
  63.  *
  64.  * @see java.lang.Object#hashCode
  65.  * @see java.lang.Object#equals
  66.  * @version     1.29, 09/28/95
  67.  * @author    Arthur van Hoff
  68.  */
  69. public
  70. class Hashtable extends Dictionary {
  71.     /**
  72.      * The hash table data.
  73.      */
  74.     private HashtableEntry table[];
  75.  
  76.     /**
  77.      * The total number of entries in the hash table.
  78.      */
  79.     private int count;
  80.  
  81.     /**
  82.      * Rehashes the table when count exceeds this threshold.
  83.      */
  84.     private int threshold;
  85.  
  86.     /**
  87.      * The load factor for the hashtable.
  88.      */
  89.     private float loadFactor;
  90.  
  91.     /**
  92.      * Constructs a new, empty hashtable with the specified initial 
  93.      * capacity and the specified load factor.
  94.      * @param initialCapacity the initial number of buckets
  95.      * @param loadFactor a number between 0.0 and 1.0, it defines
  96.      *        the threshold for rehashing the hashtable into
  97.      *        a bigger one.
  98.      * @exception IllegalArgumentException If the initial capacity
  99.      * is less than or equal to zero.
  100.      * @exception IllegalArgumentException If the load factor is
  101.      * less than or equal to zero.
  102.      */
  103.     public Hashtable(int initialCapacity, float loadFactor) {
  104.     if ((initialCapacity <= 0) || (loadFactor <= 0.0)) {
  105.         throw new IllegalArgumentException();
  106.     }
  107.     this.loadFactor = loadFactor;
  108.     table = new HashtableEntry[initialCapacity];
  109.     threshold = (int)(initialCapacity * loadFactor);
  110.     }
  111.  
  112.     /**
  113.      * Constructs a new, empty hashtable with the specified initial 
  114.      * capacity.
  115.      * @param initialCapacity the initial number of buckets
  116.      */
  117.     public Hashtable(int initialCapacity) {
  118.     this(initialCapacity, 0.75f);
  119.     }
  120.  
  121.     /**
  122.      * Constructs a new, empty hashtable. A default capacity and load factor
  123.      * is used. Note that the hashtable will automatically grow when it gets
  124.      * full.
  125.      */
  126.     public Hashtable() {
  127.     this(101, 0.75f);
  128.     }
  129.  
  130.     /**
  131.      * Returns the number of elements contained in the hashtable. 
  132.      */
  133.     public int size() {
  134.     return count;
  135.     }
  136.  
  137.     /**
  138.      * Returns true if the hashtable contains no elements.
  139.      */
  140.     public boolean isEmpty() {
  141.     return count == 0;
  142.     }
  143.  
  144.     /**
  145.      * Returns an enumeration of the hashtable's keys.
  146.      * @see Hashtable#elements
  147.      * @see Enumeration
  148.      */
  149.     public synchronized Enumeration keys() {
  150.     return new HashtableEnumerator(table, true);
  151.     }
  152.  
  153.     /**
  154.      * Returns an enumeration of the elements. Use the Enumeration methods 
  155.      * on the returned object to fetch the elements sequentially.
  156.      * @see Hashtable#keys
  157.      * @see Enumeration
  158.      */
  159.     public synchronized Enumeration elements() {
  160.     return new HashtableEnumerator(table, false);
  161.     }
  162.  
  163.     /**
  164.      * Returns true if the specified object is an element of the hashtable.
  165.      * This operation is more expensive than the containsKey() method.
  166.      * @param value the value that we are looking for
  167.      * @exception NullPointerException If the value being searched 
  168.      * for is equal to null.
  169.      * @see Hashtable#containsKey
  170.      */
  171.     public synchronized boolean contains(Object value) {
  172.     if (value == null) {
  173.         throw new NullPointerException();
  174.     }
  175.  
  176.     HashtableEntry tab[] = table;
  177.     for (int i = tab.length ; i-- > 0 ;) {
  178.         for (HashtableEntry e = tab[i] ; e != null ; e = e.next) {
  179.         if (e.value.equals(value)) {
  180.             return true;
  181.         }
  182.         }
  183.     }
  184.     return false;
  185.     }
  186.  
  187.     /**
  188.      * Returns true if the collection contains an element for the key.
  189.      * @param key the key that we are looking for
  190.      * @see Hashtable#contains
  191.      */
  192.     public synchronized boolean containsKey(Object key) {
  193.     HashtableEntry tab[] = table;
  194.     int hash = key.hashCode();
  195.     int index = (hash & 0x7FFFFFFF) % tab.length;
  196.     for (HashtableEntry e = tab[index] ; e != null ; e = e.next) {
  197.         if ((e.hash == hash) && e.key.equals(key)) {
  198.         return true;
  199.         }
  200.     }
  201.     return false;
  202.     }
  203.  
  204.     /**
  205.      * Gets the object associated with the specified key in the 
  206.      * hashtable.
  207.      * @param key the specified key
  208.      * @returns the element for the key or null if the key
  209.      *         is not defined in the hash table.
  210.      * @see Hashtable#put
  211.      */
  212.     public synchronized Object get(Object key) {
  213.     HashtableEntry tab[] = table;
  214.     int hash = key.hashCode();
  215.     int index = (hash & 0x7FFFFFFF) % tab.length;
  216.     for (HashtableEntry e = tab[index] ; e != null ; e = e.next) {
  217.         if ((e.hash == hash) && e.key.equals(key)) {
  218.         return e.value;
  219.         }
  220.     }
  221.     return null;
  222.     }
  223.  
  224.     /**
  225.      * Rehashes the content of the table into a bigger table.
  226.      * This method is called automatically when the hashtable's
  227.      * size exceeds the threshold.
  228.      */
  229.     protected void rehash() {
  230.     int oldCapacity = table.length;
  231.     HashtableEntry oldTable[] = table;
  232.  
  233.     int newCapacity = oldCapacity * 2 + 1;
  234.     HashtableEntry newTable[] = new HashtableEntry[newCapacity];
  235.  
  236.     threshold = (int)(newCapacity * loadFactor);
  237.     table = newTable;
  238.  
  239.     //System.out.println("rehash old=" + oldCapacity + ", new=" + newCapacity + ", thresh=" + threshold + ", count=" + count);
  240.  
  241.     for (int i = oldCapacity ; i-- > 0 ;) {
  242.         for (HashtableEntry old = oldTable[i] ; old != null ; ) {
  243.         HashtableEntry e = old;
  244.         old = old.next;
  245.  
  246.         int index = (e.hash & 0x7FFFFFFF) % newCapacity;
  247.         e.next = newTable[index];
  248.         newTable[index] = e;
  249.         }
  250.     }
  251.     }
  252.  
  253.     /**
  254.      * Puts the specified element into the hashtable, using the specified
  255.      * key.  The element may be retrieved by doing a get() with the same key.
  256.      * The key and the element cannot be null. 
  257.      * @param key the specified key in the hashtable
  258.      * @param value the specified element
  259.      * @exception NullPointerException If the value of the element 
  260.      * is equal to null.
  261.      * @see Hashtable#get
  262.      * @return the old value of the key, or null if it did not have one.
  263.      */
  264.     public synchronized Object put(Object key, Object value) {
  265.     // Make sure the value is not null
  266.     if (value == null) {
  267.         throw new NullPointerException();
  268.     }
  269.  
  270.     // Makes sure the key is not already in the hashtable.
  271.     HashtableEntry tab[] = table;
  272.     int hash = key.hashCode();
  273.     int index = (hash & 0x7FFFFFFF) % tab.length;
  274.     for (HashtableEntry e = tab[index] ; e != null ; e = e.next) {
  275.         if ((e.hash == hash) && e.key.equals(key)) {
  276.         Object old = e.value;
  277.         e.value = value;
  278.         return old;
  279.         }
  280.     }
  281.  
  282.     if (count >= threshold) {
  283.         // Rehash the table if the threshold is exceeded
  284.         rehash();
  285.         return put(key, value);
  286.     } 
  287.  
  288.     // Creates the new entry.
  289.     HashtableEntry e = new HashtableEntry();
  290.     e.hash = hash;
  291.     e.key = key;
  292.     e.value = value;
  293.     e.next = tab[index];
  294.     tab[index] = e;
  295.     count++;
  296.     return null;
  297.     }
  298.  
  299.     /**
  300.      * Removes the element corresponding to the key. Does nothing if the
  301.      * key is not present.
  302.      * @param key the key that needs to be removed
  303.      * @return the value of key, or null if the key was not found.
  304.      */
  305.     public synchronized Object remove(Object key) {
  306.     HashtableEntry tab[] = table;
  307.     int hash = key.hashCode();
  308.     int index = (hash & 0x7FFFFFFF) % tab.length;
  309.     for (HashtableEntry e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
  310.         if ((e.hash == hash) && e.key.equals(key)) {
  311.         if (prev != null) {
  312.             prev.next = e.next;
  313.         } else {
  314.             tab[index] = e.next;
  315.         }
  316.         count--;
  317.         return e.value;
  318.         }
  319.     }
  320.     return null;
  321.     }
  322.  
  323.     /**
  324.      * Clears the hash table so that it has no more elements in it.
  325.      */
  326.     public synchronized void clear() {
  327.     HashtableEntry tab[] = table;
  328.     for (int index = tab.length; --index >= 0; )
  329.         tab[index] = null;
  330.     count = 0;
  331.     }
  332.  
  333.     /**
  334.      * Creates a clone of the hashtable. A shallow copy is made,
  335.      * the keys and elements themselves are NOT cloned. This is a
  336.      * relatively expensive operation.
  337.      */
  338.     public synchronized Object clone() {
  339.     Hashtable t = (Hashtable)super.clone();
  340.     t.table = new HashtableEntry[table.length];
  341.     for (int i = table.length ; i-- > 0 ; ) {
  342.         t.table[i] = (table[i] != null) ? (HashtableEntry)table[i].clone() : null;
  343.     }
  344.     return t;
  345.     }
  346.  
  347.     /**
  348.      * Converts to a rather lengthy String.
  349.      */
  350.     public synchronized String toString() {
  351.     int max = size() - 1;
  352.     StringBuffer buf = new StringBuffer();
  353.     Enumeration k = keys();
  354.     Enumeration e = elements();
  355.     buf.append("{");
  356.  
  357.     for (int i = 0; i <= max; i++) {
  358.         String s1 = k.nextElement().toString();
  359.         String s2 = e.nextElement().toString();
  360.         buf.append(s1 + "=" + s2);
  361.         if (i < max) {
  362.         buf.append(", ");
  363.         }
  364.     }
  365.     buf.append("}");
  366.     return buf.toString();
  367.     }
  368. }
  369.  
  370. /**
  371.  * A hashtable enumerator class.  This class should remain opaque 
  372.  * to the client. It will use the Enumeration interface. 
  373.  */
  374. class HashtableEnumerator implements Enumeration {
  375.     boolean keys;
  376.     int index;
  377.     HashtableEntry table[];
  378.     HashtableEntry entry;
  379.  
  380.     HashtableEnumerator(HashtableEntry table[], boolean keys) {
  381.     this.table = table;
  382.     this.keys = keys;
  383.     this.index = table.length;
  384.     }
  385.     
  386.     public boolean hasMoreElements() {
  387.     if (entry != null) {
  388.         return true;
  389.     }
  390.     while (index-- > 0) {
  391.         if ((entry = table[index]) != null) {
  392.         return true;
  393.         }
  394.     }
  395.     return false;
  396.     }
  397.  
  398.     public Object nextElement() {
  399.     if (entry == null) {
  400.         while ((index-- > 0) && ((entry = table[index]) == null));
  401.     }
  402.     if (entry != null) {
  403.         HashtableEntry e = entry;
  404.         entry = e.next;
  405.         return keys ? e.key : e.value;
  406.     }
  407.     throw new NoSuchElementException("HashtableEnumerator");
  408.     }
  409.             
  410. }
  411.